package com.happy3w.java.ext.stream;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;

public class ItemCounter<T> implements Collector<T, Map<T, CountHolder<T>>, Stream<CountHolder<T>>> {

    public static <T> ItemCounter<T> counter() {
        return new ItemCounter<>();
    }

    @Override
    public Supplier<Map<T, CountHolder<T>>> supplier() {
        return () -> new HashMap<>();
    }

    @Override
    public BiConsumer<Map<T, CountHolder<T>>, T> accumulator() {
        return (m, t) -> {
            CountHolder<T> c = m.computeIfAbsent(t, key -> new CountHolder<>(key));
            c.increase(1);
        };
    }

    @Override
    public BinaryOperator<Map<T, CountHolder<T>>> combiner() {
        return (a, b)-> {
            for (Map.Entry<T, CountHolder<T>> entry : b.entrySet()) {
                T key = entry.getKey();
                CountHolder<T> countHolder = a.get(key);
                if (countHolder == null) {
                    a.put(key, entry.getValue());
                } else {
                    countHolder.increase(entry.getValue().getCount());
                }
            }
            return a;
        };
    }

    @Override
    public Function<Map<T, CountHolder<T>>, Stream<CountHolder<T>>> finisher() {
        return m -> m.values().stream();
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }

}
